package br.poli.ecomp.adssableccbuilder.builder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PushbackReader;
import java.util.Map;
import java.util.Set;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.sablecc.exception.InternalException;
import org.sablecc.sablecc.automaton.Automaton;
import org.sablecc.sablecc.exception.CompilerException;
import org.sablecc.sablecc.launcher.SableCC;
import org.sablecc.sablecc.lrautomaton.LRAutomaton;
import org.sablecc.sablecc.structure.Context;
import org.sablecc.sablecc.structure.GlobalIndex;
import org.sablecc.sablecc.syntax3.lexer.Lexer;
import org.sablecc.sablecc.syntax3.lexer.LexerException;
import org.sablecc.sablecc.syntax3.node.AGrammar;
import org.sablecc.sablecc.syntax3.node.AParser;
import org.sablecc.sablecc.syntax3.node.Start;
import org.sablecc.sablecc.syntax3.parser.Parser;
import org.sablecc.sablecc.syntax3.parser.ParserException;
import org.sablecc.util.Strictness;
import org.sablecc.util.Verbosity;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import br.poli.ecomp.ads.sableccbuilder.Activator;
import br.poli.ecomp.ads.sableccbuilder.preferences.PreferenceConstants;

public class SableCCBuilder extends IncrementalProjectBuilder {

	class SableCCDeltaVisitor implements IResourceDeltaVisitor {
		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse
		 * .core.resources.IResourceDelta)
		 */
		public boolean visit(IResourceDelta delta) throws CoreException {
			IResource resource = delta.getResource();
			switch (delta.getKind()) {
			case IResourceDelta.ADDED:
				// handle added resource
				checkSableCC(resource);
				break;
			case IResourceDelta.REMOVED:
				// handle removed resource
				break;
			case IResourceDelta.CHANGED:
				// handle changed resource
				checkSableCC(resource);
				break;
			}
			// return true to continue visiting children.
			return true;
		}
	}

	class SableCCResourceVisitor implements IResourceVisitor {
		public boolean visit(IResource resource) {
			checkSableCC(resource);
			// return true to continue visiting children.
			return true;
		}
	}

	class XMLErrorHandler extends DefaultHandler {

		private IFile file;

		public XMLErrorHandler(IFile file) {
			this.file = file;
		}

		private void addMarker(SAXParseException e, int severity) {
			SableCCBuilder.this.addMarker(file, e.getMessage(),
					e.getLineNumber(), severity);
		}

		public void error(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_ERROR);
		}

		public void fatalError(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_ERROR);
		}

		public void warning(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_WARNING);
		}
	}

	public static final String BUILDER_ID = "SableCCBuilder.SableCCBuilder";

	private static final String MARKER_TYPE = "SableCCBuilder.sableCCProblem";

	// private SAXParserFactory parserFactory;

	private void addMarker(IFile file, String message, int lineNumber,
			int severity) {
		try {
			IMarker marker = file.createMarker(MARKER_TYPE);
			marker.setAttribute(IMarker.MESSAGE, message);
			marker.setAttribute(IMarker.SEVERITY, severity);
			if (lineNumber == -1) {
				lineNumber = 1;
			}
			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
		} catch (CoreException e) {
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 * java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		if (kind == FULL_BUILD) {
			fullBuild(monitor);
		} else {
			IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				fullBuild(monitor);
			} else {
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	void checkSableCC(IResource resource) {
		if (resource instanceof IFile
				&& resource.getName().endsWith(".grammar")) {
			IFile grammarFile = (IFile) resource;
			deleteMarkers(grammarFile);
			Verbosity verbosity = Verbosity.QUIET;
			String targetLanguage = "java";
			String path = Activator
					.getDefault()
					.getPreferenceStore()
					.getString(PreferenceConstants.DIRETORIO_COMPILACAO);
			System.out.println(path);
			File destinationDirectory = new File(path);
			// default destination package is anonymous
			String destinationPackage = "";

			// XMLErrorHandler reporter = new XMLErrorHandler(grammarFile);
			Strictness strictness = Strictness.LENIENT;
			Start ast = null;

			try {
				String caminho = grammarFile.getLocation().toOSString();
				FileReader fr = new FileReader(caminho);
				BufferedReader br = new BufferedReader(fr);
				PushbackReader pbr = new PushbackReader(br, 1024);
				ast = new Parser(new Lexer(pbr)).parse();
				AGrammar node = (AGrammar) ast.getPGrammar();
				SableCCElements.extrairComponentes(node);
				pbr.close();
				br.close();
				fr.close();
				
				GlobalIndex globalIndex = SableCC.verifySemantics(ast,
						strictness);

				Context context = globalIndex.getContexts().iterator().next();
				Automaton lexer = SableCC.computeLexer(globalIndex, verbosity);
				AParser aParser = (AParser) ((AGrammar) ast.getPGrammar()).getParser();
				LRAutomaton parser=null;

				if(aParser!=null){
				parser = SableCC.computeParser(globalIndex,
						verbosity);
				}

				if (targetLanguage.equals("java")) {
					SableCC.generateJavaCode(destinationDirectory,
							destinationPackage, globalIndex, lexer, parser);
				} else {
//					throw new InternalException("unimplemented");
				}
			} catch (IOException e) {
				throw CompilerException.inputError(grammarFile.toString(), e);
			} catch (ParserException e) {
				// TODO Auto-generated catch block
//				e.printStackTrace();
				System.out.println("Parser!");
			} catch (LexerException e) {
				// TODO Auto-generated catch block
//				e.printStackTrace();
				System.out.println("Lexer!");
			} catch (Exception e) {
				System.out.println("Outro!");
			}
			

			// switch (verbosity) {
			// case VERBOSE:
			// System.out.println(" Verifying semantics");
			// break;
			// }
		}
	}

	private void deleteMarkers(IFile file) {
		try {
			file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
		} catch (CoreException ce) {
		}
	}

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		try {
			getProject().accept(new SableCCResourceVisitor());
		} catch (CoreException e) {
		}
	}

	// private SAXParser getParser() throws ParserConfigurationException,
	// SAXException {
	// if (parserFactory == null) {
	// parserFactory = SAXParserFactory.newInstance();
	// }
	// return parserFactory.newSAXParser();
	// }

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		// the visitor does the work.
		delta.accept(new SableCCDeltaVisitor());
	}
}
